/*
 * AIEngine a new generation network intrusion detection system.
 *
 * Copyright (C) 2013-2023  Luis Campo Giralte
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 * Written by Luis Campo Giralte <luis.camp0.2009@gmail.com>
 *
 * Configuration diagram of the stack
 *
 *                         +--------------------+
 *                         | TCPGenericProtocol |
 *                         +-------+------------+
 *                                 |
 *          +--------------------+ |              +--------------------+
 *          |     SSLProtocol    | |              | UDPGenericProtocol |
 *          +--------------+-----+ |              +-----------+--------+
 *                         |       |                          |
 * +--------------------+  |       |  +--------------------+  |
 * |    HTTPProtocol    |  |       |  |    DNSProtocol     |  |
 * +------------------+-+  |       |  +------------+-------+  |
 *                    |    |       |               |          |
 *                 +--+----+-------+----+    +-----+----------+---+
 *                 |    TCPProtocol     |    |    UDPProtocol     |
 *                 +------------------+-+    +-+------------------+
 *                                    |        |
 *      +--------------------+        |        |
 *      |   ICMPProtocol     +-----+  |        |
 *      +--------------------+     |  |        |
 *                               +-+--+--------+------+
 *                               |     IPProtocol     |
 *                               +---------+----------+
 *                                         |
 *                               +---------+----------+
 *                               |  EthernetProtocol  +--+
 *                               +--+-----------------+  |
 *                                  |                    |
 *                                  |          +---------+----------+
 *                                  |          |   VxLanProtocol    |
 *                                  |          +---------+----------+
 *                                  |                    |
 *                +-----------------+--+       +---------+----------+
 *                |    GREProtocol     |       |    UDPProtocol     |
 *                +-----------------+--+       +--+-----------------+
 *                                  |             |
 *                               +--+-------------+---+
 *                         +---> |     IPProtocol     | <---+
 *                         |     +---------+----------+     |
 *                         |               |                |
 *                +--------+-----------+   |   +------------+-------+
 *                |    VLANProtocol    |   |   |    MPLSProtocol    |
 *                +--------+-----------+   |   +------------+-------+
 *                         |               |                |
 *                         |     +---------+----------+     |
 *                         +-----+  EthernetProtocol  +-----+
 *                               +--------------------+
 *
 */
#ifndef SRC_STACKVIRTUAL_H_
#define SRC_STACKVIRTUAL_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <chrono>
#include <string>
#include "Multiplexer.h"
#include "FlowForwarder.h"
#include "protocols/ip/IPProtocol.h"
#include "protocols/vxlan/VxLanProtocol.h"
#include "protocols/gre/GREProtocol.h"
#include "protocols/udp/UDPProtocol.h"
#include "protocols/tcp/TCPProtocol.h"
#include "protocols/icmp/ICMPProtocol.h"
#include "flow/FlowManager.h"
#include "flow/FlowCache.h"
#include "NetworkStack.h"
#include "DatabaseAdaptor.h"

namespace aiengine {

class StackVirtual: public NetworkStack {
public:
	explicit StackVirtual();
        virtual ~StackVirtual() {}

	uint16_t getLinkLayerType() const override { return ETHERTYPE_IP; }
        MultiplexerPtrWeak getLinkLayerMultiplexer() override { return mux_eth;}

        void statistics(std::basic_ostream<char> &out) const override;

	void showFlows(std::basic_ostream<char> &out, std::function<bool (const Flow&)> condition, int protocol) const override;
	void showFlows(Json &out, std::function<bool (const Flow&)> condition, int protocol) const override;

	void setTotalTCPFlows(int value) override;
	void setTotalUDPFlows(int value) override;
        int getTotalTCPFlows() const override;
        int getTotalUDPFlows() const override;

	void setMode(const std::string &mode) override;
	const char *getMode() const override { return operation_mode_.c_str(); }

	void setFlowsTimeout(int timeout) override;
	int getFlowsTimeout() const override { return flow_table_tcp_vir_->getTimeout(); }

#if defined(BINDING)
        FlowManager &getTCPFlowManager() override { return *flow_table_tcp_vir_.get(); }
        FlowManager &getUDPFlowManager() override { return *flow_table_udp_vir_.get(); }
#else
        FlowManagerPtrWeak getTCPFlowManager() override { return flow_table_tcp_vir_; }
        FlowManagerPtrWeak getUDPFlowManager() override { return flow_table_udp_vir_; }
#endif

	void setTCPRegexManager(const SharedPointer<RegexManager> &rm) override;
        void setUDPRegexManager(const SharedPointer<RegexManager> &rm) override;

        void setTCPIPSetManager(const SharedPointer<IPSetManager> &ipset_mng) override;
        void setUDPIPSetManager(const SharedPointer<IPSetManager> &ipset_mng) override;

#if defined(RUBY_BINDING) || defined(LUA_BINDING) || defined(GO_BINDING)
        void setTCPRegexManager(RegexManager &rm) override { setTCPRegexManager(std::make_shared<RegexManager>(rm)); }
        void setUDPRegexManager(RegexManager &rm) override { setUDPRegexManager(std::make_shared<RegexManager>(rm)); }

        void setTCPIPSetManager(IPSetManager &ipset_mng) { setTCPIPSetManager(std::make_shared<IPSetManager>(ipset_mng)); }
        void setUDPIPSetManager(IPSetManager &ipset_mng) { setUDPIPSetManager(std::make_shared<IPSetManager>(ipset_mng)); }
#elif defined(JAVA_BINDING)
        void setTCPRegexManager(RegexManager *sig);
        void setUDPRegexManager(RegexManager *sig);

        void setTCPIPSetManager(IPSetManager *ipset_mng);
        void setUDPIPSetManager(IPSetManager *ipset_mng);
#endif
	std::tuple<Flow*,Flow*> getCurrentFlows() const override;
	SharedPointer<Flow> getFlow(const FlowSearchOptions &fsos) const override;
private:
	typedef NetworkStack super_;

	std::string operation_mode_ = "full";

        //Protocols
	IPProtocolPtr ip_ = IPProtocolPtr(new IPProtocol());
        UDPProtocolPtr udp_ = UDPProtocolPtr(new UDPProtocol("UDP VxLan"));
	VxLanProtocolPtr vxlan_ = VxLanProtocolPtr(new VxLanProtocol());
	GREProtocolPtr gre_ = GREProtocolPtr(new GREProtocol());
	EthernetProtocolPtr eth_vir_ = EthernetProtocolPtr(new EthernetProtocol());
	IPProtocolPtr ip_vir_ = IPProtocolPtr(new IPProtocol());
	UDPProtocolPtr udp_vir_ = UDPProtocolPtr(new UDPProtocol());
        TCPProtocolPtr tcp_vir_ = TCPProtocolPtr(new TCPProtocol());
        ICMPProtocolPtr icmp_ = ICMPProtocolPtr(new ICMPProtocol());

        // Specific Multiplexers
        MultiplexerPtr mux_udp_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_vxlan_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_gre_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_eth_vir_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_ip_vir_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_udp_vir_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_tcp_vir_ = MultiplexerPtr(new Multiplexer());
        MultiplexerPtr mux_icmp_ = MultiplexerPtr(new Multiplexer());

        // FlowManager and FlowCache
	FlowManagerPtr flow_table_udp_ = FlowManagerPtr(new FlowManager());
        FlowManagerPtr flow_table_udp_vir_ = FlowManagerPtr(new FlowManager());
        FlowManagerPtr flow_table_tcp_vir_ = FlowManagerPtr(new FlowManager());
        FlowCachePtr flow_cache_udp_ = FlowCachePtr(new FlowCache());
        FlowCachePtr flow_cache_udp_vir_ = FlowCachePtr(new FlowCache());
        FlowCachePtr flow_cache_tcp_vir_ = FlowCachePtr(new FlowCache());

        // FlowForwarders
	SharedPointer<FlowForwarder> ff_vxlan_ = SharedPointer<FlowForwarder>(new FlowForwarder());
	SharedPointer<FlowForwarder> ff_udp_ = SharedPointer<FlowForwarder>(new FlowForwarder());
        SharedPointer<FlowForwarder> ff_tcp_vir_ = SharedPointer<FlowForwarder>(new FlowForwarder());
        SharedPointer<FlowForwarder> ff_udp_vir_ = SharedPointer<FlowForwarder>(new FlowForwarder());
};

typedef std::shared_ptr<StackVirtual> StackVirtualPtr;

} // namespace aiengine

#endif  // SRC_STACKVIRTUAL_H_
